using MicroMsg.Common.Event;
using MicroMsg.Common.Utils;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
namespace MicroMsg.Network
{
	public class LongConnector
	{
		private const int CONN_RETRY_MAX = 3;
		private const int CONN_SEND_FAIL_MAX = 3;
		private const int CONN_CONNECT_FAIL_MAX = 3;
		public static SocketClient mSocketClient = null;
		private static int mReconnectLeft = 3;
		public static double mLastConnTimestamp = 0.0;
		public static double mLastConnectedTimestamp = 0.0;
		private static double mNextHelloTimestamp = 0.0;
		public static double mFirstKeepAlivePointAfterConnected = 0.0;
		private static bool mEnableConnect = false;
		private static int mConnFailedCount = 0;
		private static int mSendFailedCount = 0;
		private static bool mAvailableConnect = true;
		private static double mLastUnAvailableTimestamp = 0.0;
		public static Socket getRawSocket()
		{
			if (!LongConnector.isValid())
			{
				return null;
			}
			return LongConnector.mSocketClient.mSocket;
		}
		public static bool isValid()
		{
			return LongConnector.mSocketClient != null && LongConnector.mSocketClient.isConnect();
		}
		public static void onPrepare()
		{
			LongConnector.mReconnectLeft = 3;
		}
		private static double getSleepTime(int reconLeft)
		{
			switch (reconLeft)
			{
			case 1:
				return 25000.0;
			case 2:
				return 15000.0;
			case 3:
				return 0.0;
			default:
				return 40000.0;
			}
		}
		public static void setEnable(bool enable)
		{
			LongConnector.mEnableConnect = enable;
		}
		public static void setAvailable(bool available)
		{
			if (LongConnector.mAvailableConnect == available)
			{
				return;
			}
			LongConnector.mAvailableConnect = available;
			if (!available)
			{
				LongConnector.mLastUnAvailableTimestamp = Util.getNowMilliseconds();
			}
		}
		public static bool isAvailable()
		{
			return LongConnector.mAvailableConnect;
		}
		public static bool checkReady()
		{
			if (!LongConnector.mEnableConnect)
			{
				return false;
			}
			if (!NetworkDeviceWatcher.isNetworkAvailable())
			{
				return false;
			}
			if (!LongConnector.isAvailable())
			{
				double nowMilliseconds = Util.getNowMilliseconds();
				if (nowMilliseconds < LongConnector.mLastUnAvailableTimestamp + 600000.0)
				{
					return false;
				}
				Log.smethod_1("Network", "network device is available, but longconn is not available, try longconn per 10mintues...");
				LongConnector.setAvailable(true);
			}
			if (LongConnector.checkReadyEx())
			{
				LongConnector.checkKeepAlive();
				return true;
			}
			return false;
		}
		private static bool checkReadyEx()
		{
			if (LongConnector.isValid())
			{
				if (LongConnector.mLastConnectedTimestamp != 0.0 && SessionPack.getNow() > LongConnector.mLastConnectedTimestamp + 30000.0)
				{
					EventCenter.postEvent(EventConst.ON_NET_LONGCONN_KEEPALIVE, null, null);
					LongConnector.mLastConnectedTimestamp = 0.0;
				}
				return true;
			}
			if (LongConnector.mReconnectLeft <= 0)
			{
				if (LongConnector.mReconnectLeft == 0)
				{
					Log.smethod_1("Network", "no chance to try connect.");
					LongConnector.mReconnectLeft = -1;
				}
				return false;
			}
			double now = SessionPack.getNow();
			double num = LongConnector.mLastConnTimestamp + LongConnector.getSleepTime(LongConnector.mReconnectLeft);
			if (LongConnector.mReconnectLeft != 3 && now < num)
			{
				return false;
			}
			LongConnector.mLastConnTimestamp = now;
			LongConnector.mReconnectLeft--;
			Connector.setConnectorStatus(ConntectorStatus.Connecting);
			LongConnector.mSocketClient = new SocketClient();
			HostService.HostInfo availableHost = HostService.mLongConnHosts.getAvailableHost();
			SocketError socketError = LongConnector.mSocketClient.Connect(availableHost.mHost, availableHost.mPort);
			if (socketError == null)
			{
				Log.smethod_4("Network", "connect success.");
				LongConnector.mLastConnectedTimestamp = now;
				NetworkDeviceWatcher.onConnected();
				LongConnector.mReconnectLeft = 2;
				LongConnector.mFirstKeepAlivePointAfterConnected = LongConnector.restartKeepAlivePoint(3000);
				LongConnector.mConnFailedCount = 0;
				Connector.setConnectorStatus(ConntectorStatus.Connected);
				return true;
			}
			if (socketError == 11001)
			{
				HostService.setDNSFailed();
			}
			Log.smethod_1("Network", "connect error:" + socketError.ToString());
			LongConnector.close();
			LongConnector.mConnFailedCount++;
			if (LongConnector.mConnFailedCount >= 3)
			{
				Log.smethod_4("Network", "longconnect is not available as connect failed(3/3).");
				LongConnector.setAvailable(false);
				LongConnector.mConnFailedCount = 0;
			}
			HostService.mLongConnHosts.onCurrentHostFailed();
			Connector.setConnectorStatus(ConntectorStatus.Disconnect);
			return false;
		}
		public static void close()
		{
			if (LongConnector.mSocketClient != null)
			{
				LongConnector.mSocketClient.Close();
				LongConnector.mSocketClient = null;
				Connector.setConnectorStatus(ConntectorStatus.Disconnect);
			}
			NetworkDeviceWatcher.onConnnectClosed();
			LongConnector.stopKeepAlivePoint();
		}
		public static void onSendFailed(bool needReconnect)
		{
			LongConnector.close();
			LongConnector.mSendFailedCount++;
			if (LongConnector.mSendFailedCount >= 3)
			{
				LongConnector.mSendFailedCount = 0;
				LongConnector.setAvailable(false);
				Log.smethod_4("Network", "longconnect is not available as send failed(3/3).");
			}
			HostService.mLongConnHosts.onCurrentHostFailed();
			if (!needReconnect)
			{
				LongConnector.mReconnectLeft = 0;
			}
		}
		public static bool sendPack(SessionPack sessionPack)
		{
			if (LongConnector.mSocketClient == null)
			{
				return false;
			}
			NetPack.Request request = new NetPack.Request(sessionPack.mSeqID, sessionPack.mCmdID, sessionPack.mCacheBodyBuffer);
			byte[] array = null;
			request.serializeToBuffer(ref array);
			FlowControl.onSend(sessionPack.mCmdID, sessionPack.mCmdUri, (uint)array.Length);
			SocketError socketError = LongConnector.mSocketClient.Send(array);
			if (socketError != null)
			{
				Log.smethod_1("Network", "Socket Send error : " + socketError.ToString());
				if (socketError == 10053 || socketError == 10054)
				{
					LongConnector.close();
				}
				return false;
			}
			LongConnector.restartKeepAlivePoint(60000);
			return true;
		}
		public static bool checkKeepAlive()
		{
			if (LongConnector.mNextHelloTimestamp == 0.0)
			{
				return false;
			}
			if (SessionPack.getNow() < LongConnector.mNextHelloTimestamp)
			{
				return false;
			}
			if (SessionPackMgr.getAccount().isValid() && SessionPackMgr.isValidSessionKey())
			{
				if (LongConnector.mFirstKeepAlivePointAfterConnected == LongConnector.mNextHelloTimestamp)
				{
					EventCenter.postEvent(EventConst.ON_NET_MM_NET_NOOP, null, null);
				}
				else
				{
					EventCenter.postEvent(EventConst.ON_NET_MM_NET_NOOP, null, null);
				}
				LongConnector.restartKeepAlivePoint(60000);
				return true;
			}
			LongConnector.stopKeepAlivePoint();
			return false;
		}
		public static double restartKeepAlivePoint(int interval)
		{
			LongConnector.mNextHelloTimestamp = SessionPack.getNow() + (double)interval;
			return LongConnector.mNextHelloTimestamp;
		}
		public static void stopKeepAlivePoint()
		{
			LongConnector.mNextHelloTimestamp = 0.0;
		}
		public static void sendHelloPack()
		{
			Log.smethod_4("Network", "send hello pack... ");
			SessionPackMgr.putToTail(new SessionPack
			{
				mCmdID = 6,
				mCacheBodyBuffer = new byte[0],
				mRetryLeft = 1
			});
		}
		private static bool receiveFromSocket(ref byte[] outBuf, ref int offset, ref int count)
		{
			if (!LongConnector.isValid())
			{
				return false;
			}
			SocketError socketError = LongConnector.mSocketClient.Receive(ref outBuf, ref offset, ref count);
			if (socketError != null)
			{
				Log.smethod_1("Network", "longconn.Socket error in receive: " + socketError.ToString());
			}
			if (socketError != 10053)
			{
				if (socketError != 10054)
				{
					if (socketError == null && count != 0)
					{
						LongConnector.mSendFailedCount = 0;
						LongConnector.setAvailable(true);
						HostService.mLongConnHosts.onCurrentHostSuccess();
						return true;
					}
					return false;
				}
			}
			LongConnector.close();
			return false;
		}
		public static bool receive(List<Connector.RawPackBody> listPack)
		{
			byte[] recvBuffer = null;
			int num = 0;
			int recvCount = 0;
			if (!LongConnector.receiveFromSocket(ref recvBuffer, ref num, ref recvCount))
			{
				return false;
			}
			byte[] body = null;
			int int_ = 0;
			int int_2 = 0;
			if (!LongConnector.onReadSocket(recvBuffer, recvCount, ref body, ref int_, ref int_2))
			{
				return false;
			}
			listPack.Add(new Connector.RawPackBody
			{
				body = body,
				int_0 = int_2,
				int_1 = int_
			});
			return true;
		}
		private static bool onReadSocket(byte[] recvBuffer, int recvCount, ref byte[] outBody, ref int outSeq, ref int outCmd)
		{
			NetPack.Response response = new NetPack.Response();
			if (!response.unserializeFromBuffer(recvBuffer, recvCount))
			{
				Log.smethod_1("Network", "longconn. onReadSocket:error in unserializeFromBuffer ");
				return false;
			}
			LongConnector.restartKeepAlivePoint(60000);
			int int_ = response.getHead().int_0;
			int opCmd = response.getHead().opCmd;
			response.getLength();
			outSeq = int_;
			outCmd = opCmd;
			outBody = new byte[response.getBody().Length];
			Buffer.BlockCopy(response.getBody(), 0, outBody, 0, response.getBody().Length);
			return true;
		}
	}
}
